/**
* @file SerialPortHandler.cpp in LiveGraph
* @author linfe
* @comment
* Create on 2022/9/30 22:09
* @version 1.0
**/


#include "SerialPortHandler.h"
#include "external_pkgs.h"
#include "comm_protocol.h"
#include "glog/logging.h"
#include <QDebug>
#include <QThread>

#ifdef SIMULATE_SERIAL_INPUT
#endif


SerialPortHandler::SerialPortHandler(const QSerialPortInfo &info) : info(info) {

    baud_rate = QSerialPort::Baud115200;
    serial = nullptr;
    callback_func = {
            {comm_sync_msg_imu_id,      nullptr},
            {comm_sync_msg_pos_atti_id, nullptr},
    };

#ifdef SIMULATE_SERIAL_INPUT
    timer = nullptr;
#endif
}

SerialPortHandler::~SerialPortHandler() {
    delete serial;
    serial = nullptr;
#ifdef   SIMULATE_SERIAL_INPUT
    delete timer;
    timer = nullptr;
#endif
}

void imu_callback(uint8_t *buffer) {

}


void SerialPortHandler::handleResults() {
    uint32_t msg_id = 0;
    auto data = serial->readAll();
    if (data.isEmpty())
        return;
    monitor.updateBytesCnt(data.size());
    for (auto &d: data) {
        msg_id = handle.updateByte(d);
        if (!msg_id) {
            continue;
        }
        if (callback_func[msg_id]!= nullptr){
            callback_func[msg_id](msg_id,handle.buffer());
        }
        monitor.updateFrameCnt(msg_id);
        /* show data to LiveView*/
        switch (msg_id) {
            case comm_sync_msg_imu_id: {
                auto imu_msg = *(comm_sync_msg_imu_t *) handle.buffer();
                LiveData item{};
                auto *tm = (system_time_t *) &imu_msg.timestamp;
                item.timestamp = (tm->millisecond / 1000.0 + tm->microsecond / 1.0e6);
                item.data[0] = imu_msg.data.acce[0];
                item.data[1] = imu_msg.data.acce[1];
                item.data[2] = imu_msg.data.acce[2];
                item.data[3] = imu_msg.data.gyro[0];
                item.data[4] = imu_msg.data.gyro[1];
                item.data[5] = imu_msg.data.gyro[2];
                emit DataReady(item);
            }
                break;
            default:
                break;
        }
    }
}

void SerialPortHandler::Init() {
    qDebug() << "Initialize " << info.portName() << " baud rate" << baud_rate;
    if (!serial) {
        serial = new QSerialPort(info);
    }
    serial->setReadBufferSize(2048);
    serial->setBaudRate(baud_rate);
    connect(serial, &QSerialPort::readyRead, this, &SerialPortHandler::handleResults);
    connect(serial, &QSerialPort::errorOccurred, this, &SerialPortHandler::handleError);
#ifdef SIMULATE_SERIAL_INPUT
    serial->open(QSerialPort::ReadOnly);
#else
    serial->open(QSerialPort::ReadOnly);
#endif
    if (!serial->isOpen()) {
        LOG(INFO) << info.portName().toStdString() << " open failed:" << serial->errorString().toStdString();
        emit SerialStateChanged(serial->error());
        return;
    }
    LOG(INFO) << "Open succeed!:" << info.portName().toStdString();
    emit SerialStateChanged(serial->error());
//    monitor.Start();
#ifdef SIMULATE_SERIAL_INPUT
    if (timer) {
        timer->start();
        return;
    }else{
        timer = new QTimer();
    }
    /* 以下代码只能执行一次，否则会重复触发计时器事件*/
    connect(timer, &QTimer::timeout,this,  &SerialPortHandler::GenerateSimpleData);
    timer->start(1000 / SIMULATE_RATE);
#endif
}

void SerialPortHandler::handleError(QSerialPort::SerialPortError error) {
    if (error != QSerialPort::SerialPortError::NoError)
        LOG(ERROR) << "Error occurred:" << serial->errorString().toStdString();
    emit SerialStateChanged(error);
}

void SerialPortHandler::Stop() {
    if (serial) {
        if (serial->isOpen()) {
            serial->close();
            emit SerialStateChanged(serial->error());
        }
    }
#ifdef SIMULATE_SERIAL_INPUT
    if (timer) {
        if (timer->isActive())
            timer->stop();
    }
#endif
}

void SerialPortHandler::SetSerial(QSerialPort *serial_) {
    SerialPortHandler::serial = serial_;
}


void SerialPortHandler::SetInfo(const QSerialPortInfo &portInfo) {
    SerialPortHandler::info = portInfo;
}

SerialPortHandler::SerialPortHandler() {

    baud_rate = QSerialPort::Baud115200;
    serial = nullptr;

#ifdef SIMULATE_SERIAL_INPUT
    timer = nullptr;
#endif

}

void SerialPortHandler::SetBaudRate(QSerialPort::BaudRate rate) {
    this->baud_rate = rate;
}

bool SerialPortHandler::IsOpen() const {
    if (serial) {
        return serial->isOpen();
    }
    return false;
}

void SerialPortHandler::SerialAct(bool on) {
    if (!serial) {
        return;
    }
    if (on) {
        Init();
    } else {
        Stop();
    }
}

void SerialPortHandler::SetCallBackFunc(void *obj,uint32_t id, std::function<void(uint32_t,uint8_t *)> callbacks) {
    callback_func[id] = (callback_type )callbacks;
}

#ifdef SIMULATE_SERIAL_INPUT
void SerialPortHandler::GenerateSimpleData() {
    if (!serial->isOpen()) {
        return;
    }
    static int i = 0;
    static uint32_t ms = 0;
    static const float pi = 3.1415f;
    output_data_t sim_data = {};
    sim_data.header = 0XAA55AA55L;
    sim_data.length = sizeof(sim_data);
    ms += (1000 / SIMULATE_RATE);
    sim_data.tm.millisecond = ms;
    sim_data.tm.microsecond = 0;
    sim_data.acce[0] = (int16_t) (1024.f * sinf(2 * pi * (float) i / SIMULATE_RATE));
    sim_data.acce[1] = (int16_t) (1024.f * sinf(2 * pi * (float) i / SIMULATE_RATE + pi / 3));
    sim_data.acce[2] = (int16_t) (1024.f * sinf(2 * pi * (float) i / SIMULATE_RATE + 2 * pi / 3));
    uint32_t check_sum = app_crc32_checksum((uint8_t *) &sim_data, sizeof(output_data_t) - 4);
    auto *p = (uint8_t *) &sim_data.check_sum;
    for (int j = 0; j < 4; j++) {
        p[3 - j] = check_sum & 0xff;
        check_sum = check_sum >> 8;
    }
    i++;
    serial->write((const char *) &sim_data, sizeof(sim_data));
}
#endif

SerialMonitor::SerialMonitor() {
     total_bytes = 0;
     total_frames = 0;
     byte_rates = 0;
     frame_rates = 0;
     timer = new QTimer();
     connect(timer, SIGNAL(timeout()), this, SLOT(BeatPerSec()));

}

SerialMonitor::~SerialMonitor() {
    if(timer){
        if(timer->isActive()){
            timer->stop();
        }
        delete timer;
    }
}

void SerialMonitor::BeatPerSec() {
    byte_rates = total_bytes - total_bytes_last_sec;
    frame_rates = total_frames - total_frame_last_sec;
    total_bytes_last_sec = total_bytes;
    total_frame_last_sec = total_frames;
}

uint32_t SerialMonitor::getTotalBytes() const {
    return total_bytes;
}

uint32_t SerialMonitor::getTotalFrames() const {
    return total_frames;
}

uint32_t SerialMonitor::getByteRates() const {
    return byte_rates;
}

uint32_t SerialMonitor::getFrameRates() const {
    return frame_rates;
}

void SerialMonitor::updateBytesCnt(uint32_t cnt) {
    total_bytes += cnt;
}

void SerialMonitor::updateFrameCnt(uint32_t msg_id) {
    if(msg_id > 0){
        msg_cnt[msg_id] += 1;
        total_frames += 1;
    }
}

void SerialMonitor::Start() {
    timer->start(1000);
}
